﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml.Linq;
using WordSpider.Entities;

namespace WordSpider
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void test_Click(object sender, RoutedEventArgs e)
        {
            var client = new WebClient { Encoding = new UTF8Encoding() };
            var wordStr = client.DownloadString(@"http://dict.youdao.com/search?q=" + wordTextBox.Text);

            wordStr = RemoveEnter(wordStr);

            AddMessage(GetChinese(wordStr));
            AddMessage(GetWordGroup(wordStr));
            AddMessage(GetSampleSentence(wordStr));
        }

        /// <summary>
        /// 移除回车
        /// </summary>
        /// <param name="wordStr"></param>
        /// <returns></returns>
        private string RemoveEnter(string wordStr)
        {
            return Regex.Replace(wordStr, "\\n|\\t", "");
        }

        /// <summary>
        /// 获得例句
        /// </summary>
        /// <param name="sourceStr"></param>
        /// <returns></returns>
        private string GetSampleSentence(string sourceStr)
        {
            var sb = new StringBuilder();

            //获得例句外框
            var allSample = Regex.Match(sourceStr, "<div id=\\\"bilingual.*?>(?<content>.*?)</div>",
                                     RegexOptions.Singleline);
            //获得例句
            var samples = Regex.Matches(allSample.Value, "<li.*?>(?<onesample>.*?)</li>",
                                           RegexOptions.Singleline);
            foreach (Match match in samples)
            {
                //获得例句中文和英文
                var paragraph = Regex.Matches(match.Value, "<p>(?<paragraph>.*?)</p>",
                                 RegexOptions.Singleline);

                //获得英文
                sb.Append(GetEnglishSentense(paragraph[0].Value));

                sb.Append("  =  ");

                //获得中文
                sb.Append(GetChineseSentense(paragraph[1].Value));


                sb.AppendLine();

            }

            return sb.ToString();
        }

        /// <summary>
        /// 获得一个中文句子
        /// </summary>
        /// <param name="paragraph"></param>
        /// <returns></returns>
        private string GetChineseSentense(string paragraph)
        {
            var sb = new StringBuilder();
            var tmpP = Regex.Replace(paragraph, "<span.*?(><b>|>)(?<sen>.*?)(</b>.*?<|<)/span>",
                          new MatchEvaluator(x => x.Groups["sen"].Value), RegexOptions.Singleline);

            var match = Regex.Match(tmpP, "<p>(?<chinese>.*?)</p>", RegexOptions.Singleline);
            sb.Append(match.Groups["chinese"].Value);

            return sb.ToString();
        }

        /// <summary>
        /// 获得英文句子
        /// </summary>
        /// <param name="paragraph"></param>
        /// <returns></returns>
        private string GetEnglishSentense(string paragraph)
        {
            var sb = new StringBuilder();
            //去掉<b></b>
            paragraph = Regex.Replace(paragraph, "<b>(?<bold>.*?)</b>",
                          new MatchEvaluator(x => x.Groups["bold"].Value));


            //匹配句子
            var matches = Regex.Matches(paragraph, "<span.*?(><b>|>)(?<sen>.*?)(</b>.*?<|<)/span>",
                                         RegexOptions.Singleline);
            foreach (Match p in matches)
            {
                sb.Append(p.Groups["sen"].Value);
            }

            return sb.ToString();
        }

        /// <summary>
        /// 获得词组
        /// </summary>
        /// <param name="wordStr"></param>
        /// <returns></returns>
        private string GetWordGroup(string sourceStr)
        {
            //获得外框
            var tmpStr = Regex.Match(sourceStr, "<div id=\\\"wordGroup.*?>(?<content>.*?)</div>", RegexOptions.Singleline);
            //获得内部li
            var tmpStrList = Regex.Matches(tmpStr.Value, "<a href.*?>(?<english>.*?)</a></span>(?<chinese>.*?)</p>", RegexOptions.Singleline);

            var sb = new StringBuilder();

            foreach (Match match in tmpStrList)
            {
                sb.AppendLine(match.Groups["english"].Value + match.Groups["chinese"].Value.Trim());
            }

            if (tmpStr.Success)
            {
                return sb.ToString();
            }

            return "";
        }

        /// <summary>
        /// 获得基本的中文含义
        /// </summary>
        /// <param name="sourceStr"></param>
        /// <returns></returns>
        private string GetChinese(string sourceStr)
        {
            //获得外框
            var tmpStr = Regex.Match(sourceStr, "<div id=\\\"etcTrans.*?>(?<content>.*?)</div>", RegexOptions.Singleline);
            //获得内部li
            var tmpStrList = Regex.Matches(tmpStr.Value, "<li>(?<content>.*?)</li>", RegexOptions.Singleline);

            var sb = new StringBuilder();

            foreach (Match match in tmpStrList)
            {
                sb.AppendLine(match.Groups["content"].Value);
            }

            if (tmpStr.Success)
            {
                return sb.ToString();
            }

            return "";
        }

        /// <summary>
        /// 获得源字符串中，以特定字符开头、特定字符结尾的字符串
        /// </summary>
        /// <param name="sourceString"></param>
        /// <param name="startString"></param>
        /// <param name="endString"></param>
        /// <returns></returns>
        private List<string> GetInnerString(string sourceString, string startString, string endString)
        {
            var strings = new List<string>();
            var testString = "<div>hello</div><div>world</div>";
            var regex = new Regex(@"<div.*?>(?<content>.*?)</div>");
            var matches = regex.Matches(testString);
            foreach (Match match in matches)
            {
                strings.Add(match.Groups["content"].Value);
            }
            return strings;
        }

        private void AddMessage(string message)
        {
            this.Dispatcher.BeginInvoke(new Action(() => messageTextBlock.Text = string.Format("[{0:hh:mm:ss}] {1}\n", DateTime.Now, message) + messageTextBlock.Text));
            ;
        }

        private void ShowMessage(string message)
        {
            this.Dispatcher.BeginInvoke(new Action(() => messageTextBlock.Text = string.Format("[{0:hh:mm:ss}] {1}\n", DateTime.Now, message)));


        }

        private void addWord_Click(object sender, RoutedEventArgs e)
        {
            //TestSingleWord();

            try
            {
                WordManager.GetWord(wordTextBox.Text);
                AddMessage(wordTextBox.Text + "获取成功");

            }
            catch (Exception ex)
            {
                AddMessage(wordTextBox.Text + " " + ex.Message);
            }
        }

        private void TestSingleWord()
        {
            WordManager.AddWord(new WordEntity()
                                    {
                                        English = "hello",
                                        Chinese = "喂；哈罗",
                                        WordGroups = new List<WordGroupEntity>()
                                                         {
                                                             new WordGroupEntity()
                                                                 {
                                                                     English = "say hello",
                                                                     Chinese = "打招呼；问好"
                                                                 },
                                                             new WordGroupEntity()
                                                                 {
                                                                     English = "hello everyone",
                                                                     Chinese = "大家好"
                                                                 },
                                                         },
                                        Sentences = new List<SentenceEntity>()
                                                        {
                                                            new SentenceEntity()
                                                                {
                                                                    English = "Hello , what can I do for you ? ",
                                                                    Chinese = "你好，我能为你做些什么吗？"
                                                                },
                                                            new SentenceEntity()
                                                                {
                                                                    English = "Hello , Susan , this is reception . ",
                                                                    Chinese = "你好！苏珊，我是接待员。"
                                                                },
                                                        },
                                    });
            AddMessage("新单词添加成功");
        }

        private void addMultiWord_Click(object sender, RoutedEventArgs e)
        {
            var thread = new Thread(DownloadWords);
            thread.Start();
        }

        private void getFromDB_Click(object sender, RoutedEventArgs e)
        {
            //AddMessage(WordManager.GetWord(wordTextBox.Text).ToXML());
            new Thread(AnalysisWords).Start();

        }



        private void upgradeWord_Click(object sender, RoutedEventArgs e)
        {
            Thread thread = new Thread(UpgreadWord);
            thread.Start();
        }

        private void upgradeHtml_Click(object sender, RoutedEventArgs e)
        {
            new Thread(AnalysisWords).Start();
        }

        private void downloadByBook_Click(object sender, RoutedEventArgs e)
        {
            new Thread(DownloadWords).Start();
        }

        private void generateXML_Click(object sender, RoutedEventArgs e)
        {
            GenerateXML(5);

            AddMessage("成功生成完全版xml");
        }

        private void generateFreeXML_Click(object sender, RoutedEventArgs e)
        {
            GenerateXML(1);

            AddMessage("成功生成免费版xml");
        }

        #region private method

        /// <summary>
        /// 下载、分析、生成xml
        /// </summary>
        private void DownloadAnalysisCreateWords()
        {
            var bookWords = new List<BookWordRelation>();
            var words = new List<WordEntity>();

            foreach (var bookEntity in WordManager.GetAllBook().Where(x => x.IsInput))
            {
                //从输入文件中获得英语集合
                var englishs = GetEnglishFromFile(bookEntity.FileName);

                //下载单词集合，从数据库或网络获得
                words.AddRange(CreateWords(englishs));

                //生成最终的xml文件
                CreateXMLFile(words, bookEntity);

                //添加到映射集合中
                englishs.ForEach(x => bookWords.Add(new BookWordRelation()
                                                        {
                                                            BookId = bookEntity.BookId,
                                                            English = x,
                                                        }));

            }
            //生成图书-单词的映射xml文件
            CreateRelationXMLFile(bookWords);
        }

        /// <summary>
        /// 下载所有单词，已经存在的不下载
        /// </summary>
        private void DownloadWords()
        {
            //找出需要下载的单词
            var englishList = GetTotalEnglish().GroupJoin(new WordSpiderDBEntities().Table_English.Select(x => x.English).ToList(),
                x => x, x => x, (x, y) => new { English = x, Enumer = y })
                .Where(x => !x.Enumer.Any()).Select(x => x.English).ToList();

            AddMessage(string.Format("共{0}个单词需要下载", englishList.Count.ToString()));

            //从有道下载单词
            AddMessage("开始下载");
            WordManager.DownloadHtmlAndSaveToDB(englishList, i => this.Dispatcher.BeginInvoke(new Action(() =>
                                                                                                  {
                                                                                                      downloadByBook.
                                                                                                          Content =
                                                                                                          i.ToString();
                                                                                                  })));

            AddMessage("下载完成");
        }

        /// <summary>
        /// 下载例句
        /// </summary>
        private void DownloadSentences()
        {
            //找出需要下载的单词
            var englishList = GetTotalEnglish().Join(new WordSpiderDBEntities()
                .Table_English.Select(x => new { x.English, x.BingSentenceHtml }).ToList(),
                x => x, x => x.English, (x, y) => new { y.English, y.BingSentenceHtml })
                .Where(x => x.BingSentenceHtml == null).Select(x => x.English).ToList();

            AddMessage(string.Format("共{0}个单词需要从bing下载句子", englishList.Count.ToString()));

            AddMessage("开始下载");
            WordManager.DownloadBingSentencesJsonSaveToDB(englishList,
                i => this.Dispatcher.BeginInvoke(new Action(() =>
                        {
                            downloadByBing.Content = i.ToString();
                        })));

        }

        /// <summary>
        /// 从图书中，获得所有不重复的英文单词
        /// </summary>
        /// <returns></returns>
        private List<string> GetTotalEnglish()
        {
            var englishList = new List<string>();
            foreach (var bookEntity in WordManager.GetAllBook().Where(x => x.IsInput))
            {
                //从输入文件中获得英语集合
                englishList.AddRange(GetEnglishFromFile(bookEntity.FileName));
            }

            //排除重复单词
            return englishList.Distinct().ToList();
        }


        /// <summary>
        /// 生成XML文件
        /// </summary>
        private void GenerateXML(int sentenceCount)
        {
            //获得输入文件所有的单词
            var words = GetTotalEnglish().Join(WordManager.GetAllWord(), x => x, x => x.English, (x, y) => y).ToList();

            //生成词典的xml
            CreateDictionaryXMLFile(words, sentenceCount);

            //生成图书-单词的映射xml文件
            CreateRelationXMLFile();
        }

        /// <summary>
        /// 生成图书-单词的映射xml文件
        /// </summary>
        private void CreateRelationXMLFile()
        {
            var bookWords = new List<BookWordRelation>();

            foreach (var bookEntity in WordManager.GetAllBook().Where(x => x.IsInput))
            {
                //从输入文件中获得英语集合
                var englishs = GetEnglishFromFile(bookEntity.FileName);

                //添加到映射集合中
                englishs.ForEach(x => bookWords.Add(new BookWordRelation()
                                                        {
                                                            BookId = bookEntity.BookId,
                                                            English = x,
                                                        }));
            }

            CreateRelationXMLFile(bookWords);
        }

        /// <summary>
        /// 生成单词的xml文件
        /// </summary>
        /// <param name="words"></param>
        private static void CreateDictionaryXMLFile(List<WordEntity> words, int setenceCount)
        {
            //var bookWordsElement = new XElement("Words");
            //words.ForEach(x => bookWordsElement.Add(x.ToXElementFree(true, true, false)));

            words.GroupBy(x => x.English.ToLower()[0]).ToList()
                 .ForEach(x =>
                             {
                                 var letter = x.Key.ToString();
                                 var bookWordsElement = new XElement("Words");
                                 x.ToList().ForEach(y => bookWordsElement.Add(y.ToXElementFree(true, true, false, setenceCount)));
                                 bookWordsElement.Save(Environment.CurrentDirectory + @"\Dictionary\" + letter + ".xml");
                             });


        }

        /// <summary>
        /// 生成图书-单词的映射xml文件
        /// </summary>
        /// <param name="bookWords"></param>
        private static void CreateRelationXMLFile(List<BookWordRelation> bookWords)
        {
            bookWords.GroupBy(x => x.BookId).ToList()
                .ForEach(x =>
                             {
                                 var bookWordsElement = new XElement("BookWords");
                                 x.ToList().ForEach(y => bookWordsElement.Add(y.ToXElement()));
                                 bookWordsElement.Save(Environment.CurrentDirectory + @"\relation\" + x.Key + ".xml");
                             });

        }

        /// <summary>
        /// 从输入文件中获得英语集合
        /// </summary>
        /// <returns></returns>
        private List<string> GetEnglishFromFile(string fileName)
        {
            var englishs = new List<string>();

            //打开文件，循环，去除空行，去除重复记录
            using (var sr = new StreamReader(Environment.CurrentDirectory + @"\input\" + fileName))
            {
                //统计单词数
                while (true)
                {
                    //拿到单词
                    var word = sr.ReadLine();
                    if (word == null) break;
                    if (word.Trim() != "")
                    {
                        englishs.Add(word.Trim());
                    }
                }
            }

            //排除重复的单词
            englishs = englishs.Distinct().ToList();

            this.Dispatcher.BeginInvoke(new Action(() => AddMessage(string.Format("{0}文件中共{1}个单词", fileName, englishs.Count))));
            return englishs;
        }

        /// <summary>
        /// 下载单词集合
        /// </summary>
        /// <param name="englishs"></param>
        /// <returns></returns>
        private List<WordEntity> CreateWords(List<string> englishs)
        {
            var words = new List<WordEntity>();
            englishs.ForEach(x =>
                                 {
                                     try
                                     {
                                         //开始下载，加入到集合中
                                         words.Add(WordManager.GetWord(x));
                                         //修改下载计数器
                                         this.Dispatcher.BeginInvoke(new Action(() =>
                                                                                    {
                                                                                        addMultiWord.Content =
                                                                                            words.Count.ToString();
                                                                                    }));
                                     }
                                     catch (Exception ex)
                                     {
                                         //记录下载异常的信息
                                         this.Dispatcher.BeginInvoke(new Action(() => AddMessage(x + "下载异常\n" + ex.Message)));
                                     }
                                 });


            this.Dispatcher.BeginInvoke(new Action(() => AddMessage(string.Format("共{0}个单词下载完成", words.Count))));
            return words;
        }

        /// <summary>
        /// 生成最终的xml文件
        /// </summary>
        /// <param name="words"></param>
        /// <param name="bookEntity"> </param>
        private void CreateXMLFile(List<WordEntity> words, BookEntity bookEntity)
        {
            var wordsElement = new XElement("Words");

            words.ForEach(x =>
                              {
                                  try
                                  {
                                      wordsElement.Add(x.ToXElement());
                                  }
                                  catch (Exception ex)
                                  {
                                      //记录下载异常的信息
                                      this.Dispatcher.BeginInvoke(
                                          new Action(() => AddMessage(x.English + "生成xml异常\n" + ex.Message)));
                                  }
                              });

            wordsElement.Save(Environment.CurrentDirectory + @"\" + bookEntity.BookId + ".xml");
            this.Dispatcher.BeginInvoke(new Action(() => AddMessage("文件生成成功！")));
        }

        /// <summary>
        /// 升级
        /// </summary>
        private void UpgreadWord()
        {
            WordManager.UpgradeWord(x => this.Dispatcher.BeginInvoke(new Action(() => AddMessage("共" + x.ToString() + "条"))),
                                     x => this.Dispatcher.BeginInvoke(new Action(() =>
                                     {
                                         upgradeWord.Content =
                                             x.ToString();
                                     })));
            AddMessage("词库升级完成");
        }

        private void UpgradeWordHtml()
        {
            WordManager.UpgradeWordForDownloadHtml(
                x => this.Dispatcher.BeginInvoke(new Action(() => AddMessage("共" + x.ToString() + "条"))),
                x => this.Dispatcher.BeginInvoke(new Action(() =>
                                                                {
                                                                    upgradeHtml.Content =
                                                                        x.ToString();
                                                                })));
            AddMessage("词库升级完成");
        }

        #endregion

        /// <summary>
        /// 分析数据库中的单词
        /// </summary>
        private void AnalysisWords()
        {
            AddMessage("开始分析");

            var db = new WordSpiderDBEntities();
            var query = db.Table_English.Where(x => x.CompleteData == null);
            var count = 0;

            var totalCount = query.Count();

            AddMessage(string.Format("共{0}个单词需要分析", totalCount));

            while (true)
            {
                var result = query.Take(100).ToList();

                if (result.Count == 0) break;

                //获得需要升级的单词
                result.ForEach(x =>
                     {
                         try
                         {
                             x.CompleteData = WordDownloadManager.AnalysisHtml(x.English, x.SourceHtml).ToXML();

                             count++;
                         }
                         catch (Exception ex)
                         {
                             AddMessage(string.Format("{0}单词分析失败!!!   {1}", x.English, ex.Message));
                         }
                     });

                //升级单词
                db.SaveChanges();
            }

            AddMessage(string.Format("{0}个单词分析成功", count));
        }


        private void checkXML_Click(object sender, RoutedEventArgs e)
        {
            AddMessage("开始分析数据库的XML文件");

            var db = new WordSpiderDBEntities();

            //数据库内容太多，需要分页处理
            var total = db.Table_English.Count();

            for (var i = 0; i < total; i += 500)
            {
                var wordList = db.Table_English.OrderBy(x => x.English).Skip(i).Take(500)
                    .Select(x => new { English = x.English, CompleteData = x.CompleteData }).ToList();

                foreach (var tableEnglish in wordList)
                {
                    try
                    {
                        if (!WordDownloadManager.CheckXML(tableEnglish.CompleteData))
                        {
                            AddMessage(string.Format(" {0} 单词分析失败，需要检查中文为空", tableEnglish.English));
                        }
                    }
                    catch (Exception)
                    {
                        AddMessage(string.Format(" {0} 单词分析失败，异常抛出", tableEnglish.English));
                    }
                }

            }



            AddMessage("XML分析完成");

        }


        #region Bing 处理
        private void downloadByBing_Click(object sender, RoutedEventArgs e)
        {
            new Thread(DownloadSentences).Start();

            //获得Json字符串
            //var client = new WebClient();
            //client.Encoding = new UTF8Encoding();
            //client.Headers.Add("Content-Type", @"application/x-www-form-urlencoded");
            //var str = client.UploadString(@"http://dict.bing.com.cn/io.aspx", "POST",
            //                              "q=carry out&t=dict&ut=sent&sc=all&ss=dict&sd=300&ofst=0&ulang=ZH-CN&tlang=EN-US");
            ////q=gross&t=dict&ut=sent&sc=all&ss=dict&sd=300&ofst=0&ulang=ZH-CN&tlang=EN-US
            //AddMessage(str);


            //解析句子
            //var colletion = Regex.Matches(str, "{\"D\":{\"\\$\":\"(?<sent>.*?)\"}", RegexOptions.Singleline);

            //foreach (Match match in colletion)
            //{
            //    //解析句子2
            //    var sent = match.Groups["sent"].Value;
            //    sent = Regex.Replace(sent, @"(?<start>{\d+#|\$\d+}|{#\*|\*\$}|{##\*|\*\$\$})", "", RegexOptions.Singleline);

            //    AddMessage(sent);
            //}
        }



        private void analyzeBingJson_Click(object sender, RoutedEventArgs e)
        {
            new Thread(() =>
                           {
                               var db = new WordSpiderDBEntities();
                               int index = 0;

                               //获得需要处理的单词
                               var tablewordList = db.Table_English.Where(x => x.BingSentenceHtml != null)
                                   .Select(x => new { x.English, x.CompleteData, x.BingSentenceHtml }).ToList()
                                   .Select(x => new Table_English()
                                                    {
                                                        English = x.English,
                                                        //CompleteData = x.CompleteData,
                                                        BingSentenceHtml = x.BingSentenceHtml,
                                                    })
                                   .ToList();
                               AddMessage(string.Format("共 {0} 个单词需要处理", tablewordList.Count));


                               foreach (var tablewordEntity in tablewordList)
                               {
                                   try
                                   {
                                       //分析
                                       var sents = AnalyzeSent(tablewordEntity);

                                       //保存
                                       var saveDb = new WordSpiderDBEntities();

                                       var saveEntity = saveDb.Table_English.First(x => x.English == tablewordEntity.English);
                                       var wordEntity = WordEntity.FromTable(saveEntity);
                                       wordEntity.Sentences = sents;
                                       saveEntity.CompleteData = wordEntity.ToXML();

                                       saveDb.SaveChanges();
                                   }
                                   catch (Exception ex)
                                   {
                                       AddMessage(string.Format("exception: {0} {1}", tablewordEntity.English,
                                                                ex.Message));
                                   }

                                   Dispatcher.BeginInvoke(new Action(() =>
                                                                         {
                                                                             (sender as Button).Content =
                                                                                 (++index).ToString();
                                                                         }));
                               }


                               AddMessage("处理完成");
                           }).Start();
        }

        /// <summary>
        /// 分析句子
        /// </summary>
        /// <param name="tablewordEntity"></param>
        /// <returns></returns>
        private List<SentenceEntity> AnalyzeSent(Table_English tablewordEntity)
        {
            var sents = new List<SentenceEntity>();

            var cnCollection = Regex.Matches(tablewordEntity.BingSentenceHtml, "\"CN\":{\"D\":{\"\\$\":\"(?<sent>.*?)\"}",
                                             RegexOptions.Singleline);
            var enCollection = Regex.Matches(tablewordEntity.BingSentenceHtml, "\"EN\":{\"D\":{\"\\$\":\"(?<sent>.*?)\"}",
                                             RegexOptions.Singleline);

            for (var i = 0; i < cnCollection.Count; i++)
            {
                sents.Add(new SentenceEntity()
                              {
                                  English = GetSentenceByBing(tablewordEntity.English, enCollection[i]),
                                  Chinese = GetSentenceByBing(tablewordEntity.English, cnCollection[i]),
                              });
            }
            return sents;
        }

        private string GetSentenceByBing(string english, Match sentMatch)
        {
            var result = Regex.Replace(sentMatch.Groups["sent"].Value, @"(?<start>{\d+#|\$\d+}|{#\*|\*\$}|{##\*|\*\$\$})", "", RegexOptions.Singleline);
            result = HttpUtility.UrlDecode(result);

            if (result.Contains("{") || result.Contains("#"))
            {
                AddMessage(string.Format("含有特殊符号 {0}", english));
            }

            return result;
        }

        #endregion


    }
}
